wayland: Fix top-most-popup check
authorJonas Ådahl <jadahl@gmail.com>
Sun, 16 Feb 2020 15:24:12 +0000 (16:24 +0100)
committerJonas Ådahl <jadahl@gmail.com>
Wed, 19 Feb 2020 08:47:18 +0000 (09:47 +0100)
We can map a non-grabbing popup wherever, it's just the grabbing
popup-chain that needs to be ensured not to break any ordering rules.

Fix this by managing two lists; one of open popups, and another for
grabbing ones.

gdk/wayland/gdkdisplay-wayland.h
gdk/wayland/gdksurface-wayland.c

index 1da3e36fe85915c5d5cb2ae451882ad3c09d230f..aa5797a3319abb7213f2a4465c002153af71eda0 100644 (file)
@@ -127,6 +127,7 @@ struct _GdkWaylandDisplay
   GList *orphan_dialogs;
 
   GList *current_popups;
+  GList *current_grabbing_popups;
 
   struct wl_cursor_theme *cursor_theme;
   gchar *cursor_theme_name;
index c29331441dc883261b5d3906316d83e043ca72da..267943799e89f44eecd13ea0e3f7d44ddb257fe1 100644 (file)
@@ -2184,6 +2184,21 @@ create_dynamic_positioner (GdkSurface *surface)
   g_assert_not_reached ();
 }
 
+static gboolean
+can_map_grabbing_popup (GdkSurface *surface,
+                        GdkSurface *parent)
+{
+  GdkDisplay *display = gdk_surface_get_display (surface);
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  GdkSurface *top_most_popup;
+
+  if (!display_wayland->current_grabbing_popups)
+    return TRUE;
+
+  top_most_popup = g_list_first (display_wayland->current_grabbing_popups)->data;
+  return top_most_popup == parent;
+}
+
 static void
 gdk_wayland_surface_create_xdg_popup (GdkSurface     *surface,
                                       GdkSurface     *parent,
@@ -2210,13 +2225,11 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface     *surface,
       g_warning ("Can't map popup, already mapped");
       return;
     }
+
   if (grab_input_seat &&
-      ((display->current_popups &&
-        g_list_last (display->current_popups)->data != parent) ||
-       (!display->current_popups &&
-        !is_realized_toplevel (parent))))
+      !can_map_grabbing_popup (surface, parent))
     {
-      g_warning ("Tried to map a popup with a non-top most parent");
+      g_warning ("Tried to map a grabbing popup with a non-top most parent");
       return;
     }
 
@@ -2291,6 +2304,11 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface     *surface,
 
   impl->popup_parent = parent;
   display->current_popups = g_list_append (display->current_popups, surface);
+  if (grab_input_seat)
+    {
+      display->current_grabbing_popups =
+        g_list_prepend (display->current_grabbing_popups, surface);
+    }
 }
 
 static GdkWaylandSeat *
@@ -2490,6 +2508,8 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
           impl->display_server.xdg_popup = NULL;
           display_wayland->current_popups =
             g_list_remove (display_wayland->current_popups, surface);
+          display_wayland->current_grabbing_popups =
+            g_list_remove (display_wayland->current_grabbing_popups, surface);
         }
       if (impl->display_server.xdg_surface)
         {
@@ -2512,6 +2532,8 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
           impl->display_server.zxdg_popup_v6 = NULL;
           display_wayland->current_popups =
             g_list_remove (display_wayland->current_popups, surface);
+          display_wayland->current_grabbing_popups =
+            g_list_remove (display_wayland->current_grabbing_popups, surface);
         }
       if (impl->display_server.zxdg_surface_v6)
         {